Skip to content

[TRTLLMINF-191][infra] Use native pytest capture for S3 logs - #16739

Open
niukuo wants to merge 5 commits into
NVIDIA:mainfrom
niukuo:test_output
Open

[TRTLLMINF-191][infra] Use native pytest capture for S3 logs#16739
niukuo wants to merge 5 commits into
NVIDIA:mainfrom
niukuo:test_output

Conversation

@niukuo

@niukuo niukuo commented Jul 22, 2026

Copy link
Copy Markdown
Collaborator

Description

The existing S3 plugin maintains its own session-level and per-test FD capture
machinery alongside pytest capture. This duplicates pytest lifecycle handling,
adds per-test capture overhead, and makes report sections and upload state harder
to keep consistent.

This PR switches S3 test logs to pytest's native --capture=fd output and
transforms the resulting report sections:

  • Small stdout/stderr sections remain inline; larger streams are replaced with
    one S3 URL per stream and attempt.
  • Duplicate and cumulative report sections are uploaded once.
  • Deferred uploads use a bounded worker pool and retain failed uploads in a
    recoverable spool.
  • Parent runners drain pending spool files after pytest exits.
  • Stdout and stderr are each merged across pytest phases while preserving their
    own ordering.

DETAILED_LOG keeps its existing live-console purpose. When it is enabled, the
Jenkins command retains -s and deliberately omits --capture=fd and the
per-test S3 upload arguments; native FD capture and live console output cannot
both own the same descriptors.

Abrupt termination limitation

The plugin only receives native captured output after pytest creates a report
for a phase. If pytest is terminated with os._exit, SIGKILL, or a stage-level
kill while a phase is still running, that phase produces no report and its
in-flight output cannot be transformed or recovered by --drain-spool.

This differs from the implementation currently on main: -s there does not
send S3-enabled test output directly to Jenkins because the early
SessionCapture redirects FD 1/2 into named .s3-spool files. A hard-killed
test is therefore also absent from the live console, but its raw session spool
can remain in results-*.tar.gz. With native pytest capture, the underlying
temporary capture file may disappear with the pytest process, so that artifact
fallback is no longer guaranteed. This is an explicit tradeoff of removing the
bespoke capture layer; live hard-kill diagnostics require a separate FD-level
tee design. Pytest's tee-sys mode is not sufficient because it does not cover
native FD writes, MPI workers, or subprocess output.

The previous enableS3EchoStdout parameter is also removed. It defaulted to
disabled and depended on the legacy capture implementations removed here.

Test Coverage

  • tests/unittest/test_s3_output.py covers inline output, stream merging,
    duplicate reports, reruns, failed-output tails, deferred uploads, and spool
    recovery.
  • tests/integration/defs/test_unittests.py exercises nested pytest capture and
    pending-upload draining.
  • pre-commit run --files jenkins/L0_Test.groovy

PR Checklist

  • The PR description explains the behavior and known tradeoffs.
  • The change follows the TensorRT-LLM coding guidelines.
  • Relevant test coverage is included.

@niukuo
niukuo requested review from a team as code owners July 22, 2026 14:05
@niukuo

niukuo commented Jul 22, 2026

Copy link
Copy Markdown
Collaborator Author

/bot run --disable-fail-fast

@coderabbitai

coderabbitai Bot commented Jul 22, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review

Walkthrough

Changes

The S3 pytest integration now transforms captured report sections, inlines or spools output, supports synchronous and deferred uploads, and drains pending spool files. Jenkins and integration runners enable FD capture and perform cleanup. Unit tests cover transformation, recovery, reruns, registration, and xdist behavior.

S3 deferred output workflow

Layer / File(s) Summary
Report transformation and upload plugin
tests/test_common/s3_output.py
UploadLogPlugin transforms pytest report sections, inlines small output, spools larger output, uploads synchronously or asynchronously, and exposes revised registration and CLI options.
Pending spool recovery
tests/test_common/s3_output.py
drain_pending_uploads discovers orphaned spool files, validates ownership, uploads them concurrently, and removes completed spool state.
Pytest and Jenkins execution wiring
tests/test_common/s3_output_hooks.py, tests/integration/defs/test_unittests.py, jenkins/L0_Test.groovy, jenkins/scripts/slurm_run.sh
Pytest workers register the plugin, commands use --capture=fd with deferred S3 uploads, and runners drain pending uploads after execution.
Upload behavior validation
tests/unittest/test_s3_output.py
Tests validate report transformation, upload modes, rerun handling, spool recovery, capture requirements, and xdist registration.

Estimated code review effort: 4 (Complex) | ~60 minutes

Sequence Diagram(s)

sequenceDiagram
  participant Jenkins
  participant Pytest
  participant UploadLogPlugin
  participant Spool
  participant S3
  Jenkins->>Pytest: enable capture=fd and deferred S3 upload
  Pytest->>UploadLogPlugin: process pytest report sections
  UploadLogPlugin->>Spool: write oversized captured output
  UploadLogPlugin->>S3: upload or schedule deferred upload
  Jenkins->>Spool: drain pending uploads after pytest
  Spool->>S3: upload orphaned files
Loading

Possibly related PRs

Suggested reviewers: qijune, schetlur-nv, zhanruisunch

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Title check ✅ Passed The title clearly summarizes the primary change: replacing custom capture with native pytest capture for S3 logs.
Description check ✅ Passed The description explains the problem, implementation, limitation, test coverage, and relevant checklist items.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Comment @coderabbitai help to get the list of available commands.

@tensorrt-cicd

Copy link
Copy Markdown
Collaborator

PR_Github #60995 [ run ] triggered by Bot. Commit: 19e1af6 Link to invocation

@tensorrt-cicd

Copy link
Copy Markdown
Collaborator

PR_Github #60995 [ run ] completed with state FAILURE. Commit: 19e1af6
/LLM/main/L0_MergeRequest_PR pipeline #49254 completed with status: 'FAILURE'

CI Report

⚠️ Action Required:

  • Please check the failed tests and fix your PR
  • If you cannot view the failures, ask the CI triggerer to share details
  • Once fixed, request an NVIDIA team member to trigger CI again

CI Agent Failure Analysis

Link to invocation

@tensorrt-cicd

Copy link
Copy Markdown
Collaborator

PR_Github #61007 [ run ] triggered by Bot. Commit: e9e5dd1 Link to invocation

@tensorrt-cicd

Copy link
Copy Markdown
Collaborator

PR_Github #61007 [ run ] completed with state FAILURE. Commit: e9e5dd1
/LLM/main/L0_MergeRequest_PR pipeline #49265 completed with status: 'FAILURE'

CI Report

⚠️ Action Required:

  • Please check the failed tests and fix your PR
  • If you cannot view the failures, ask the CI triggerer to share details
  • Once fixed, request an NVIDIA team member to trigger CI again

CI Agent Failure Analysis

Link to invocation

@tensorrt-cicd

Copy link
Copy Markdown
Collaborator

PR_Github #61180 [ run ] triggered by Bot. Commit: ba8cca9 Link to invocation

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@tests/test_common/s3_output.py`:
- Around line 268-274: Update the hashlib.md5 call in normalize_test_name to
pass usedforsecurity=False, preserving the existing nodeid-derived suffix and
filename normalization behavior.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Enterprise

Run ID: 67cdefca-2930-4fea-beb8-6027f9e62363

📥 Commits

Reviewing files that changed from the base of the PR and between e9e5dd1 and ba8cca9.

📒 Files selected for processing (7)
  • jenkins/L0_Test.groovy
  • jenkins/scripts/slurm_run.sh
  • tests/integration/defs/test_unittests.py
  • tests/test_common/s3_output.py
  • tests/test_common/s3_output_hooks.py
  • tests/unittest/test_s3_output.py
  • tests/unittest/tools/test_test_to_stage_mapping.py
🚧 Files skipped from review as they are similar to previous changes (3)
  • tests/integration/defs/test_unittests.py
  • jenkins/L0_Test.groovy
  • tests/test_common/s3_output_hooks.py

Comment thread tests/test_common/s3_output.py
@tensorrt-cicd

Copy link
Copy Markdown
Collaborator

PR_Github #61248 [ run ] triggered by Bot. Commit: ba8cca9 Link to invocation

@tensorrt-cicd

Copy link
Copy Markdown
Collaborator

PR_Github #61180 [ run ] completed with state ABORTED. Commit: ba8cca9

Link to invocation

@tensorrt-cicd

Copy link
Copy Markdown
Collaborator

PR_Github #61248 [ run ] completed with state FAILURE. Commit: ba8cca9
/LLM/main/L0_MergeRequest_PR pipeline #49486 completed with status: 'FAILURE'

CI Report

⚠️ Action Required:

  • Please check the failed tests and fix your PR
  • If you cannot view the failures, ask the CI triggerer to share details
  • Once fixed, request an NVIDIA team member to trigger CI again

CI Agent Failure Analysis

Link to invocation

@tensorrt-cicd

Copy link
Copy Markdown
Collaborator

PR_Github #61338 [ run ] triggered by Bot. Commit: e764c3c Link to invocation

@tensorrt-cicd

Copy link
Copy Markdown
Collaborator

PR_Github #61338 [ run ] completed with state FAILURE. Commit: e764c3c
/LLM/main/L0_MergeRequest_PR pipeline #49565 completed with status: 'FAILURE'

CI Report

⚠️ Action Required:

  • Please check the failed tests and fix your PR
  • If you cannot view the failures, ask the CI triggerer to share details
  • Once fixed, request an NVIDIA team member to trigger CI again

CI Agent Failure Analysis

Link to invocation

@tensorrt-cicd

Copy link
Copy Markdown
Collaborator

PR_Github #61449 [ run ] triggered by Bot. Commit: e764c3c Link to invocation

@tensorrt-cicd

Copy link
Copy Markdown
Collaborator

PR_Github #61449 [ run ] completed with state SUCCESS. Commit: e764c3c
/LLM/main/L0_MergeRequest_PR pipeline #49671 completed with status: 'FAILURE'

CI Report

⚠️ Action Required:

  • Please check the failed tests and fix your PR
  • If you cannot view the failures, ask the CI triggerer to share details
  • Once fixed, request an NVIDIA team member to trigger CI again

CI Agent Failure Analysis

Link to invocation

@tensorrt-cicd

Copy link
Copy Markdown
Collaborator

PR_Github #61495 [ run ] triggered by Bot. Commit: e764c3c Link to invocation

@tensorrt-cicd

Copy link
Copy Markdown
Collaborator

PR_Github #61495 [ run ] completed with state SUCCESS. Commit: e764c3c
/LLM/main/L0_MergeRequest_PR pipeline #49714 completed with status: 'FAILURE'

CI Report

⚠️ Action Required:

  • Please check the failed tests and fix your PR
  • If you cannot view the failures, ask the CI triggerer to share details
  • Once fixed, request an NVIDIA team member to trigger CI again

CI Agent Failure Analysis

Link to invocation

@tensorrt-cicd

Copy link
Copy Markdown
Collaborator

PR_Github #61540 [ run ] triggered by Bot. Commit: e764c3c Link to invocation

@tensorrt-cicd

Copy link
Copy Markdown
Collaborator

PR_Github #61540 [ run ] completed with state SUCCESS. Commit: e764c3c
/LLM/main/L0_MergeRequest_PR pipeline #49751 completed with status: 'SUCCESS'

CI Report

Link to invocation

Comment thread jenkins/scripts/slurm_run.sh
@tensorrt-cicd

Copy link
Copy Markdown
Collaborator

PR_Github #62381 [ run ] triggered by Bot. Commit: 6106fa2 Link to invocation

@tensorrt-cicd

Copy link
Copy Markdown
Collaborator

PR_Github #62381 [ run ] completed with state FAILURE. Commit: 6106fa2
/LLM/main/L0_MergeRequest_PR pipeline #50545 completed with status: 'FAILURE'

CI Report

⚠️ Action Required:

  • Please check the failed tests and fix your PR
  • If you cannot view the failures, ask the CI triggerer to share details
  • Once fixed, request an NVIDIA team member to trigger CI again

CI Agent Failure Analysis

Link to invocation

@tensorrt-cicd

Copy link
Copy Markdown
Collaborator

PR_Github #62658 [ run ] triggered by Bot. Commit: 6106fa2 Link to invocation

@tensorrt-cicd

Copy link
Copy Markdown
Collaborator

PR_Github #62658 [ run ] completed with state SUCCESS. Commit: 6106fa2
/LLM/main/L0_MergeRequest_PR pipeline #50797 completed with status: 'FAILURE'

CI Report

⚠️ Action Required:

  • Please check the failed tests and fix your PR
  • If you cannot view the failures, ask the CI triggerer to share details
  • Once fixed, request an NVIDIA team member to trigger CI again

CI Agent Failure Analysis

Link to invocation

@tensorrt-cicd

Copy link
Copy Markdown
Collaborator

PR_Github #62710 [ run ] triggered by Bot. Commit: 6106fa2 Link to invocation

@tensorrt-cicd

Copy link
Copy Markdown
Collaborator

PR_Github #62710 [ run ] completed with state SUCCESS. Commit: 6106fa2
/LLM/main/L0_MergeRequest_PR pipeline #50846 completed with status: 'FAILURE'

CI Report

⚠️ Action Required:

  • Please check the failed tests and fix your PR
  • If you cannot view the failures, ask the CI triggerer to share details
  • Once fixed, request an NVIDIA team member to trigger CI again

CI Agent Failure Analysis

Link to invocation

@tensorrt-cicd

Copy link
Copy Markdown
Collaborator

PR_Github #62807 [ run ] triggered by Bot. Commit: 6106fa2 Link to invocation

@tensorrt-cicd

Copy link
Copy Markdown
Collaborator

PR_Github #62807 [ run ] completed with state FAILURE. Commit: 6106fa2
/LLM/main/L0_MergeRequest_PR pipeline #50933 completed with status: 'FAILURE'

CI Report

⚠️ Action Required:

  • Please check the failed tests and fix your PR
  • If you cannot view the failures, ask the CI triggerer to share details
  • Once fixed, request an NVIDIA team member to trigger CI again

CI Agent Failure Analysis

Link to invocation

@BowenFu

BowenFu commented Aug 5, 2026

Copy link
Copy Markdown

Reviewed the whole change. Moving off the bespoke session-capture machinery onto native pytest capture is the right call, and the -815 in s3_output.py plus the -90 in s3_output_hooks.py are real simplification. Three things on the default path, one of them a knob that stops working.

1. --capture=fd silently disables the existing DETAILED_LOG filter.

getPytestBaseCommandLine puts the detailed-log flag near the front of testCmdLine:

testFilter[(DETAILED_LOG)] ? "-s" : "",

and appends extraArgs last (L0_Test.groovy:1392-1394), which is where --capture=fd now arrives. -s is store_const(const="no", dest="capture") and --capture writes the same dest, so last-one-wins and --capture=fd overrides it. Because ENABLE_UPLOAD_TEST_RESULTS defaults to true (:49), that is the default configuration for every stage.

On main there is no conflict: the S3 branch also added -s, so a DETAILED_LOG run passed -s twice and worked. After this PR, someone selecting DETAILED_LOG to debug a stage gets captured output instead and no indication why. If the intent is that --capture=fd is mandatory whenever --s3-upload-path is set — which register_plugin now enforces with raise ValueError("--s3-upload-path requires pytest --capture=fd") — then DETAILED_LOG needs to either suppress the S3 args or fail loudly, rather than being quietly overridden.

2. Output from a test that never finishes is now lost rather than already in the console log.

The plugin only observes output at pytest_runtest_logreport (s3_output.py:639), reading report.sections (:566) — i.e. after a test phase completes. Under -s on main, test stdout/stderr goes straight to the process stdout and is in the Jenkins console log as it is produced, so when a hanging test gets SIGKILLed by the stage timeout, everything it printed up to that point survives. Under --capture=fd it sits in pytest's fd buffer until the phase ends; a kill takes the buffer with it.

--drain-spool does not cover this. drain_pending_uploads walks .s3-spool-* for existing upload-config.json directories (:129-135), and spool files are only written from _append_capture on the report path — so it recovers completed-but-unuploaded tests, not the in-flight one. That is the case that matters most here: this repo has dedicated timeout machinery (results-timeout.xml, generateTimeoutTestResultXml, and the recent work to name the in-flight test in the timeout report) because hangs are a recurring problem, and this makes the hanging test the one whose output you can no longer see.

Worth saying explicitly in the description whether that trade was intended. --capture=tee-sys would keep both, at the cost of duplicating output into the console.

3. -o console_output_style=progress-even-when-capture-no now contradicts its own configuration.

:1390-1392 still injects it under the same ENABLE_UPLOAD_TEST_RESULTS guard that now sets --capture=fd. That option exists to fix progress rendering when capture is off; paired with --capture=fd it is a leftover from the -s era. Harmless, but it is the kind of stale pairing that makes the next reader think capture is still disabled.

Minor: removing the enableS3EchoStdout build parameter drops an operator-facing toggle with no replacement. It defaulted to false, so no default behaviour changes and I am not treating it as a regression — but if anyone was flipping it in the Jenkins UI to debug, that path is gone and the tests that asserted the wiring existed go with it (test_test_to_stage_mapping.py, -30).

The test_unittests.py hunk is fine — s3_output_module and inner_output_dir are both assigned under the same if s3_upload_path: guard that gates the finally, so the closure can't hit an unbound name. Bounded ThreadPoolExecutor and delete-only-after-successful-upload in deferred mode both look right.

Not blocking on 3 or the minor. 1 is a working knob that stops working on the default path; 2 is a diagnosability trade that should at least be a stated decision.

@niukuo

niukuo commented Aug 6, 2026

Copy link
Copy Markdown
Collaborator Author

Addressed the actionable points in fc4e1e8dd1:

  • DETAILED_LOG now preserves -s on both the SBATCH and regular platform paths by omitting native FD capture and per-test S3 arguments.
  • Removed the stale console_output_style=progress-even-when-capture-no setting.
  • Updated the PR description to document the removal of enableS3EchoStdout and the abrupt-termination limitation.

One clarification on the before/after behavior: S3-enabled main does pass -s, but pytest_load_initial_conftests starts the named-file SessionCapture when capture is no, and pytest_sessionstart redirects FD 1/2 back into that spool. Therefore an in-flight hard-kill was not live in the Jenkins console on main; its raw session output could instead survive under .s3-spool in results-*.tar.gz. Native pytest FD capture removes that artifact fallback because no report is produced and its temporary capture file may disappear with the process.

tee-sys is not an equivalent replacement because it does not capture native FD writes, MPI workers, or subprocess output. A live hard-kill diagnostic path would require a separate FD-level tee design.

niukuo added 5 commits August 6, 2026 17:19
Signed-off-by: Yiteng Niu <6831097+niukuo@users.noreply.github.com>
Signed-off-by: Yiteng Niu <6831097+niukuo@users.noreply.github.com>
Signed-off-by: Yiteng Niu <6831097+niukuo@users.noreply.github.com>
Signed-off-by: Yiteng Niu <6831097+niukuo@users.noreply.github.com>
Signed-off-by: Yiteng Niu <6831097+niukuo@users.noreply.github.com>
@tensorrt-cicd

Copy link
Copy Markdown
Collaborator

PR_Github #64295 [ run ] triggered by Bot. Commit: d8f47c6 Link to invocation

@tensorrt-cicd

Copy link
Copy Markdown
Collaborator

PR_Github #64295 [ run ] completed with state SUCCESS. Commit: d8f47c6
/LLM/main/L0_MergeRequest_PR pipeline #52195 completed with status: 'FAILURE'

CI Report

⚠️ Action Required:

  • Please check the failed tests and fix your PR
  • If you cannot view the failures, ask the CI triggerer to share details
  • Once fixed, request an NVIDIA team member to trigger CI again

CI Agent Failure Analysis

Link to invocation

@tensorrt-cicd

Copy link
Copy Markdown
Collaborator

PR_Github #64461 [ run ] triggered by Bot. Commit: d8f47c6 Link to invocation

@tensorrt-cicd

Copy link
Copy Markdown
Collaborator

PR_Github #64461 [ run ] completed with state FAILURE. Commit: d8f47c6
/LLM/main/L0_MergeRequest_PR pipeline #52333 completed with status: 'UNSTABLE'

CI Report

⚠️ Multi-GPU Label Required:
Multi-GPU tests require the ci: full pre-merge approved label on this PR. Ask a member of NVIDIA/trt-llm-ci-approvers to add the label, then re-trigger CI with the same bot command (no rebase needed).

⚠️ Action Required:

  • Please check the failed tests and fix your PR
  • If you cannot view the failures, ask the CI triggerer to share details
  • Once fixed, request an NVIDIA team member to trigger CI again

Link to invocation

@brnguyen2 brnguyen2 left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The core rewrite is sound and the unit coverage (phase merging, cumulative-section dedup, reruns, deferred backpressure, drain ownership) is convincing. The description accurately states the hard-kill tradeoff, and dropping test_s3_stdout_echo_requires_explicit_opt_in is consistent with the deleted groovy lines.

My concerns are concentrated on the recovery path — the drain exists for abruptly terminated pytest runs, but the wiring leaves it uncovered in the most likely termination scenarios:

  1. Direct CI: the drain runs after the rerun logic, which can rethrow and skip it (inline comment).
  2. Sbatch: the only drain is per-rank in slurm_run.sh, which never runs on a walltime kill or stage-level scancel. The Slurm cleanup (rm -rf ${jobWorkspace}, L0_Test.groovy:742) doesn't know about the sibling spool dir, so orphaned .s3-spool-${jobUID} directories accumulate unboundedly in /home/svc_tensorrt/bloom/scripts/ on every cluster. Please add spool-root removal to cleanupCommands (the path is derivable from jobWorkspace), or drain from the login node before cleanup.

One placement decision worth documenting: the spool root is a sibling of --output-dir, so leftover spool files are also absent from results-*.tar.gz. Combined with the documented hard-kill limitation, a killed test's completed-phase output can now vanish with no artifact fallback at all if the drain also fails. If keeping the spool out of the results tarball is intentional, a sentence in the module docstring would save the next reader the archaeology.

Comment thread jenkins/L0_Test.groovy
if (ENABLE_UPLOAD_TEST_RESULTS) {
sh """
python3 ${llmSrc}/tests/test_common/s3_output.py \
--drain-spool "${WORKSPACE}/${stageName}" || true

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This drain is skipped on the crash paths it exists for. If the regular tests fail and rerunFailedTests crashes without producing a results file, it rethrows (L0_Test.groovy:3785) out of the catch above, and execution never reaches this block — exactly the scenario (pytest died mid-run) that leaves deferred spool files behind. runIsolatedTests throwing has the same effect. Suggest wrapping the test-execution section in try { ... } finally { <drain> } so recovery always runs.

pytest_exit_code=$?
echo "Rank${SLURM_PROCID} Pytest finished execution with exit code $pytest_exit_code"
python3 "$llmSrcNode/tests/test_common/s3_output.py" \
--drain-spool "$jobWorkspace" || true

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This per-rank drain never runs when the Slurm job hits walltime or is scancel'd — the abrupt-termination case the spool is designed for. Since the spool root is a sibling of $jobWorkspace (_spool_root puts it at <parent>/.s3-spool-<name>), the existing cleanup rm -rf ${jobWorkspace} (L0_Test.groovy:742) doesn't remove it, so orphaned .s3-spool-${jobUID} dirs accumulate unboundedly in /home/svc_tensorrt/bloom/scripts/ on every cluster. Add spool-root removal to cleanupCommands, and consider a login-node drain there too so those logs are recovered rather than deleted.

streams[stream_key] = stream
else:
if stream.finalized:
raise RuntimeError(f"Captured output arrived after {stream.filename} was finalized")

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Raising here propagates out of pytest_runtest_logreport processing and becomes a pytest internal error, breaking reporting (and log upload) for the test. This plugin is log-shipping infrastructure — an unforeseen plugin interaction that delivers a late section should degrade, not fail the run. Suggest logger.warning(...) and either appending anyway or dropping the section.

config = json.load(config_file)
owner_host = config.get("hostname")
owner_pid = int(config.get("pid", 0))
if owner_host != current_host or (owner_pid and _process_is_alive(owner_pid)):

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

PID-reuse caveat: if the recorded pid has been recycled by an unrelated live process on the same host, the drain skips this spool — and for inner (nested-pytest) spools there is no later retry, so the logs are stranded and the dead report URLs stay dead. Probably acceptable given the short window between pytest exit and drain, but worth a comment; recording the process start time alongside the pid would close it if it ever bites.

return False
finally:
if s3_output_module is not None:
s3_output_module.drain_pending_uploads(

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

drain_pending_uploads isn't fully exception-proof (e.g. _create_s3_client raises RuntimeError when boto3 is missing, and its per-config except doesn't cover that). An exception raised here in the finally replaces the function's return — turning the graceful return False failure report into a test error. Wrap this call in a try/except Exception: log since it's best-effort by design.

def _resume_session_capture(self):
if self._session_capture is not None:
self._session_capture.resume_parent()
def _write_spool_file(self, test_name: str, filename: str, content: str) -> str:

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

_write_spool_file has no production callers — only the unit tests use it to fabricate leftover spool files (test_s3_output.py:469,493). Those tests could use _append_spool_file (identical except O_TRUNC vs O_APPEND on a fresh file); dropping this method removes ~15 duplicated lines.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

7 participants